package cc.shacocloud.mirage.restful.util;

import cc.shacocloud.mirage.utils.AntPathMatcher;
import cc.shacocloud.mirage.utils.PathMatcher;
import cc.shacocloud.mirage.utils.map.ConcurrentReferenceHashMap;
import org.jetbrains.annotations.NotNull;

import java.util.Comparator;
import java.util.Map;

/**
 * vertx 路径匹配器
 * <p>
 * 内部使用 AntPathMatcher，匹配时将 Vertx 路径表达式替换为 ant 路径表达式进行替换
 *
 * @author 思追(shaco)
 */
public class VertxPathMatcher implements PathMatcher {
    
    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();
    
    private final Map<String, String> patternCache = new ConcurrentReferenceHashMap<>(256);
    
    @Override
    public boolean isPattern(String path) {
        return antPathMatcher.isPattern(patternReplace(path));
    }
    
    @Override
    public boolean match(String pattern, String path) {
        return antPathMatcher.match(patternReplace(pattern), path);
    }
    
    @Override
    public boolean matchStart(String pattern, String path) {
        return antPathMatcher.matchStart(patternReplace(pattern), path);
    }
    
    @Override
    public String extractPathWithinPattern(String pattern, String path) {
        return antPathMatcher.extractPathWithinPattern(patternReplace(pattern), path);
    }
    
    @Override
    public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
        return antPathMatcher.extractUriTemplateVariables(patternReplace(pattern), path);
    }
    
    @Override
    public Comparator<String> getPatternComparator(String path) {
        return antPathMatcher.getPatternComparator(patternReplace(path));
    }
    
    /**
     * 将 vertx path 模式替换为 ant 路径模式
     * <p>
     * 例如：
     * vertx path ==> /api/users/:id
     * ant path ==> /api/users/{id}
     */
    private @NotNull String patternReplace(@NotNull String pattern) {
        return patternCache.computeIfAbsent(pattern, k -> {
            int length = k.length();
            
            StringBuilder builder = new StringBuilder();
            
            boolean varStart = false;
            for (int i = 0; i < length; i++) {
                char c = k.charAt(i);
                
                if (c == ':') {
                    varStart = true;
                    builder.append("{");
                } else if (c == '/' && varStart) {
                    builder.append("}/");
                    varStart = false;
                } else {
                    builder.append(c);
                }
            }
            
            if (varStart) {
                builder.append("}");
            }
            
            return builder.toString();
        });
    }
    
    @Override
    public String combine(String pattern1, String pattern2) {
        // TODO 暂不支持...
        throw new UnsupportedOperationException();
    }
}
